#include "cBicho.h"
#include "cScene.h"
#include "Globals.h"
#include "Physics.h"
#include "Projectile.h"

cBicho::cBicho(void)
{
	seq=0;
	delay=0;

	mp_collider = new Collider();

	jumping = false;
	m_type = PLAYER;
	m_life = 100;
}
cBicho::~cBicho(void)
{
	delete(mp_collider);
}

cBicho::cBicho(int posx,int posy,int width,int height, Type type)
{
	seq = 0;
	delay = 0;
	mp_collider = new Collider(posx, posy, posx + width - width%STEP_LENGTH, posy + height - height%JUMP_STEP);
	m_type = type;
	jumping = false;
	m_life = 100;
}
void cBicho::SetPosition(int posx,int posy)
{
	int w, h;
	GetWidthHeight(&w, &h);
	mp_collider->SetCoordinates(posx, posy, posx+w, posy+h);
}
void cBicho::GetPosition(int *posx,int *posy)
{
	int * coordinates = mp_collider->GetCoordinates();
	*posx = coordinates[0];
	*posy = coordinates[1];
	delete(coordinates);
}

Collider * cBicho::GetCollider()
{
	return mp_collider;
}

void cBicho::SetType(Type type)
{
	m_type = type;
}

cBicho::Type cBicho::GetType()
{
	return m_type;
}

void cBicho::SetTile(int tx,int ty)
{
	int w, h;
	GetWidthHeight(&w, &h);
	mp_collider->SetCoordinates(tx * TILE_SIZE, ty * TILE_SIZE, tx * TILE_SIZE + w, ty * TILE_SIZE + h);
}
void cBicho::GetTile(int *tx,int *ty)
{
	int * coordinates = mp_collider->GetCoordinates();
	*tx = coordinates[0] / TILE_SIZE;
	*ty = coordinates[1] / TILE_SIZE;
	delete(coordinates);
}
void cBicho::SetWidthHeight(int width,int height)
{
	int x, y;
	GetPosition(&x, &y);
	mp_collider->SetCoordinates(x, y, x + width - width%STEP_LENGTH, y + height - height%JUMP_STEP);
}
void cBicho::GetWidthHeight(int *width,int *height)
{
	int x, y;
	GetPosition(&x, &y);
	int * coordinates = mp_collider->GetCoordinates();
	*width = (int)abs(x - coordinates[2]);
	*height = (int)abs(y - coordinates[3]);
	delete(coordinates);
}
bool cBicho::Collides(cRect *rc)
{
	return mp_collider->Collides(new Collider(rc->left, rc->bottom, rc->right, rc->top));
}
bool cBicho::CollidesMapWall(Tile *map, bool right)
{
	if (right) return Physics::IsCollidingStatic(map, SCENE_WIDTH, SCENE_HEIGHT, mp_collider, Physics::HorizontalPositive);
	else return Physics::IsCollidingStatic(map, SCENE_WIDTH, SCENE_HEIGHT, mp_collider, Physics::HorizontalNegative);
}

bool cBicho::CollidesMapFloor(Tile *map)
{
	Tile * collidingTile = Physics::IsCollidingStatic(map, SCENE_WIDTH, SCENE_HEIGHT, mp_collider, Physics::VerticalNegative);
	if (collidingTile)
	{
		int * tileCoordinates = collidingTile->GetCollider()->GetCoordinates();
		int x, y;
		GetPosition(&x, &y);
		y = tileCoordinates[3];
		delete(tileCoordinates);
		SetPosition(x, y);
		return true;
	}
	else return false;
}

void cBicho::GetArea(cRect *rc)
{
	int x, y, w, h;
	GetPosition(&x, &y);
	GetWidthHeight(&w, &h);
	rc->left   = x;
	rc->right  = x+w;
	rc->bottom = y;
	rc->top    = y+h;
}
void cBicho::DrawRect(int tex_id,float xo,float yo,float xf,float yf)
{
	int screen_x, screen_y;
	int x, y, w, h;
	GetPosition(&x, &y);
	GetWidthHeight(&w, &h);

	screen_x = x + SCENE_Xo;
	screen_y = y + SCENE_Yo + (BLOCK_SIZE - TILE_SIZE);

	glEnable(GL_TEXTURE_2D);
	
	glBindTexture(GL_TEXTURE_2D,tex_id);
	glBegin(GL_QUADS);	
		glTexCoord2f(xo,yo);	glVertex2i(screen_x  ,screen_y);
		glTexCoord2f(xf,yo);	glVertex2i(screen_x+w,screen_y);
		glTexCoord2f(xf,yf);	glVertex2i(screen_x+w,screen_y+h);
		glTexCoord2f(xo,yf);	glVertex2i(screen_x  ,screen_y+h);
	glEnd();

	glDisable(GL_TEXTURE_2D);
}

void cBicho::DrawRect(int tex_id, float xo, float yo, float xf, float yf, int w, int h)
{
	int screen_x, screen_y;
	int x, y;
	GetPosition(&x, &y);

	screen_x = x + SCENE_Xo;
	screen_y = y + SCENE_Yo + (BLOCK_SIZE - TILE_SIZE);

	glEnable(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, tex_id);
	glBegin(GL_QUADS);
	glTexCoord2f(xo, yo);	glVertex2i(screen_x, screen_y);
	glTexCoord2f(xf, yo);	glVertex2i(screen_x + w, screen_y);
	glTexCoord2f(xf, yf);	glVertex2i(screen_x + w, screen_y + h);
	glTexCoord2f(xo, yf);	glVertex2i(screen_x, screen_y + h);
	glEnd();

	glDisable(GL_TEXTURE_2D);
}

void cBicho::DrawRect(int tex_id, float xo, float yo, float xf, float yf, int w, int h, float alpha)
{
	int screen_x, screen_y;
	int x, y;
	GetPosition(&x, &y);

	screen_x = x + SCENE_Xo;
	screen_y = y + SCENE_Yo + (BLOCK_SIZE - TILE_SIZE);
	glPushMatrix();
	glTranslatef(screen_x, screen_y, 0);
	glRotatef(alpha*RAD2DEG, 0, 0, 1);
	glTranslatef(-screen_x, -screen_y, 0);
	glEnable(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, tex_id);
	glBegin(GL_QUADS);
	glTexCoord2f(xo, yo);	glVertex2i(screen_x, screen_y);
	glTexCoord2f(xf, yo);	glVertex2i(screen_x + w, screen_y);
	glTexCoord2f(xf, yf);	glVertex2i(screen_x + w, screen_y + h);
	glTexCoord2f(xo, yf);	glVertex2i(screen_x, screen_y + h);
	glEnd();

	glDisable(GL_TEXTURE_2D);
	glPopMatrix();
}

void cBicho::MoveLeft(Tile *map)
{
	if (m_state != STATE_HURT)
	{
		int xaux;
		int x, y, w, h;
		GetPosition(&x, &y);
		GetWidthHeight(&w, &h);


		xaux = x;
		x -= STEP_LENGTH;
		mp_collider->SetCoordinates(x, y, x + w, y + h);

		if (CollidesMapWall(map, false))
		{
			x = xaux;
			mp_collider->SetCoordinates(x, y, x + w, y + h);
			m_state = STATE_LOOKLEFT;
		}
		else
		{
			if (m_state != STATE_WALKLEFT && m_state != STATE_JUMPINGLEFT)
			{
				m_state = (m_state == STATE_JUMPINGRIGHT) ? STATE_JUMPINGLEFT : STATE_WALKLEFT;
				seq = 0;
				delay = 0;
			}
		}
	}
}
void cBicho::MoveRight(Tile *map)
{
	if (m_state != STATE_HURT)
	{
		int xaux;
		int x, y, w, h;
		GetPosition(&x, &y);
		GetWidthHeight(&w, &h);

		xaux = x;
		x += STEP_LENGTH;
		mp_collider->SetCoordinates(x, y, x + w, y + h);

		if (CollidesMapWall(map, true))
		{
			x = xaux;
			mp_collider->SetCoordinates(x, y, x + w, y + h);
			m_state = STATE_LOOKRIGHT;
		}
		else
		{
			if (m_state != STATE_WALKRIGHT && m_state != STATE_JUMPINGRIGHT)
			{
				m_state = (m_state == STATE_JUMPINGLEFT) ? STATE_JUMPINGRIGHT : STATE_WALKRIGHT;
				seq = 0;
				delay = 0;
			}
		}
	}
}
void cBicho::Stop()
{
	switch(m_state)
	{
		case STATE_WALKLEFT:	
			m_state = STATE_LOOKLEFT;		
			break;
		case STATE_WALKRIGHT:	
			m_state = STATE_LOOKRIGHT;	
			break;
	}
}

void cBicho::LoadAnimations(){}

void cBicho::Draw(int n){}

cBicho * cBicho::Shoot(float velocityX, float velocityY)
{
	int x, y;
	int * coordinates = mp_collider->GetCoordinates();
	x = coordinates[0] + abs(coordinates[0] - coordinates[2]) / 2;
	y = coordinates[1] + abs(coordinates[1] - coordinates[3]) / 2;
	delete(coordinates);
	return new Projectile(x,y,velocityX,velocityY);
}

void cBicho::Jump(Tile *map)
{
	if(!jumping && m_state != STATE_HURT)
	{
		if(CollidesMapFloor(map))
		{
			jumping = true;
			m_state = (m_state == STATE_WALKRIGHT || m_state == STATE_LOOKRIGHT) ? STATE_JUMPINGRIGHT : STATE_JUMPINGLEFT;
			jump_alfa = 0;
			int * coordinates = mp_collider->GetCoordinates();
			jump_y = coordinates[1];
			delete(coordinates);
		}
	}
}
void cBicho::Logic(Tile *map)
{	
	float alfa;
	int x, y, w, h;
	GetPosition(&x, &y);
	GetWidthHeight(&w, &h);
	if (m_state == STATE_HURT)
	{
		if (m_inmunityCountdown++ == 30)
		{
			m_state = m_statePreviousToInmunity;
			m_inmunityCountdown = 0;
		}
	}
	Collider * collidingObject = Physics::IsCollidingDynamic(mp_collider, Physics::All);
	if (collidingObject)
	{
		int objectX, objectY;
		int * objectCoordinates = collidingObject->GetCoordinates();
		objectX = objectCoordinates[0];
		objectY = objectCoordinates[1];
		delete(objectCoordinates);
		switch (collidingObject->GetType())
		{
			case Collider::ENEMYPROJECTILE:
			case Collider::ENEMY:
				if (m_state != STATE_HURT)
				{
					m_life -= 5;
					m_statePreviousToInmunity = m_state;
					m_state = STATE_HURT;
					m_inmunityCountdown = 0;
					if (jumping) jumping = false;
					if (objectX >= x)
					{
						int auxX = x;
						SetPosition(x - TILE_SIZE, y);
						if (CollidesMapWall(map, false))
						{
							SetPosition(auxX, y);
						}
					}
					else
					{
						int auxX = x;
						SetPosition(x + TILE_SIZE, y);
						if (CollidesMapWall(map, true))
						{
							SetPosition(auxX, y);
						}
					}
					
				}
				break;
			case Collider::POWERUP:
				break;
			default:
				break;
		}
	}
	if(jumping)
	{
		jump_alfa += JUMP_STEP;
		
		if(jump_alfa == 180)
		{
			m_state = m_state==STATE_JUMPINGLEFT ? STATE_LOOKLEFT : STATE_LOOKRIGHT;
			jumping = false;
			y = jump_y;
			mp_collider->SetCoordinates(x, y, x + w, y + h);
		}
		else
		{
			alfa = ((float)jump_alfa) * 0.017453f;
			int auxy = y;
			y = jump_y + (int)(((float)JUMP_HEIGHT) * sin(alfa));
			mp_collider->SetCoordinates(x, y, x + w, y + h);
			
			if(jump_alfa > 90)
			{
   				jumping = !CollidesMapFloor(map);
				if (m_state == STATE_JUMPINGLEFT)
				{
					m_state = jumping ? STATE_JUMPINGLEFT : STATE_LOOKLEFT; 
				}
				if (m_state == STATE_JUMPINGRIGHT)
				{
					m_state = jumping ? STATE_JUMPINGRIGHT : STATE_LOOKRIGHT;
				}
			}
			else
			{
				if (Physics::IsCollidingStatic(map, SCENE_WIDTH, SCENE_HEIGHT, mp_collider, Physics::VerticalPositive))
				{
					jumping = false;
					mp_collider->SetCoordinates(x, auxy, x + w, auxy + h);
					m_state = (m_state == STATE_JUMPINGLEFT) ? STATE_LOOKLEFT : STATE_LOOKRIGHT;
				}
			}
		}
	}
	else
	{
		if (!CollidesMapFloor(map))
		{
			y -= (2 * STEP_LENGTH);
			mp_collider->SetCoordinates(x, y, x + w, y + h);
		}
	}
}
int cBicho::NextFrame(int max)
{
	delay++;
	if(delay == FRAME_DELAY)
	{
		seq++;
		seq%=max;		
		delay = 0;
	}
	return seq;
}
int cBicho::GetFrame()
{
	return seq;
}
cBicho::State cBicho::GetState()
{
	return m_state;
}
void cBicho::SetState(cBicho::State state)
{
	m_state = state;
}

bool cBicho::IsColliding(Tile *map)
{
	return (CollidesMapFloor(map) || CollidesMapWall(map, true) || CollidesMapWall(map, false));
}

int cBicho::GetLife()
{
	return m_life;
}

void cBicho::SetLife(int life)
{
	m_life = life;
}